package SFT;
import java.io.File;
import java.io.IOException;

import WavFile.WavFile;
import WavFile.WavFileException;

/**This is an implementation of the generic Function interface which handles a WAV file
 * and creates a 'Function' object out of it.
 */

public class WAVFunction extends abstractFunction {
	
	private double[] buffer;
	private int numChannels;
	private int channelNumber;
	private int maxVal;
	
	
	/* The constructor receives the filename of the WAV file, the supNorm and the relevant 
	 * ChannelNumber upon which the algorithm would be applied.
	 * The entire file is copied into a buffer.
	 */
	public WAVFunction(String filename, int channelNumber) {
		this.channelNumber=channelNumber;
		try {
			WavFile wavFile = WavFile.openWavFile(new File(filename));
			this.numChannels=wavFile.getNumChannels();
			buffer = new double[(int) wavFile.getNumFrames() * numChannels];
			this.maxVal=(int) wavFile.getNumFrames()-1;
			wavFile.readFrames(buffer, (int) wavFile.getNumFrames() * numChannels);
			wavFile.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (WavFileException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	
	/*This function retrieves the value from the buffer computed in the constructor
	 * the function returns the frame, according to the given ChannelNumber
	 * 
	 * */
	
	public Complex apply(int i) {
		double num=buffer[i*numChannels+channelNumber];
		return new Complex(num, 0);
	}
	


	@Override
	public int maxVal() {
		return this.maxVal;
	}
	/*exports an object of type OutputClass to a wav file at location "path", with given sampleRate*/
	public static void exportToWAV(String path, OutputClass out) {
		try{
			// Calculate the number of frames required for specified duration
			long numFrames = 0;
			for (TimeElements tm : out.getFrameList()) {
				if(tm.getTo()>numFrames)
					numFrames=(long) tm.getTo();
			}
			numFrames+=1;

			// Create a wav file with the name specified as the first argument
			WavFile wavFile = WavFile.newWavFile(new File(path), 1, numFrames, 16, out.getSampleRate());
			double[] buffer;

			// Loop until all tm's written
			for (TimeElements tm : out.getFrameList()) {
				int toWrite = (int) tm.getLength();
				buffer=new double[toWrite];
				// Fill the buffer, with the function described by the tm's heavy coefficients
				for (int s=0 ; s<toWrite ; s++)
				{
					buffer[s] = 0;
					for (Double key : tm.getHeavyCoeffs().keySet()) {
						buffer[s]+=Complex.Mult(tm.getHeavyCoeffs().get(key), Complex.Chi(key, s, 1)).Re();
						
					}
				}

				// Write the buffer
				wavFile.writeFrames(buffer, toWrite);
			}

			// Close the wavFile
			wavFile.close();
		}
		catch (Exception e)
		{
			System.err.println(e);
		}
		
	}
}
